001 /** 002 * Created by IntelliJ IDEA. 003 * User: Wei Wang 004 * Date: Jan 15, 2003 005 * Time: 1:19:37 PM 006 * Some codes are attributed to ClassPathExplorer.java in Bruno Dufour's AdaptC toolkit. 007 * please refer to http://www.sable.mcgill.ca/~bdufou1/ for more details 008 */ 009 010 package EVolve.util.sourcebrowser; 011 012 import org.apache.bcel.classfile.*; 013 import java.util.*; 014 import java.util.zip.*; 015 import java.io.*; 016 import EVolve.util.settings.SceneSetting; 017 import EVolve.Scene; 018 019 public class ClassExplorer { 020 private HashMap mapClassToSourcename; 021 private ArrayList classPath,sourcePath; 022 private static ClassExplorer instance = null; 023 024 public ClassExplorer() { 025 mapClassToSourcename = new HashMap(); 026 classPath = new ArrayList(); 027 sourcePath = new ArrayList(); 028 } 029 030 public static ClassExplorer v() { 031 if (instance == null) instance = new ClassExplorer(); 032 return instance; 033 } 034 035 public String getSourceFileFromClass(String className) { 036 prepareClassPath(); 037 prepareSourcePath(); 038 039 if (!mapClassToSourcename.containsKey(className)) { 040 041 JavaClass javaClass = loadClass(className); 042 043 if (javaClass != null) { 044 String sourceName = javaClass.getSourceFileName(); 045 boolean fileFound = false; 046 047 for (int i=0; i<sourcePath.size(); i++) { 048 String path = (String)sourcePath.get(i)+File.separatorChar+sourceName; 049 File f = new File(path); 050 if (f.exists()) { 051 mapClassToSourcename.put(className, path); 052 fileFound = true; 053 break; 054 } 055 } 056 057 if (!fileFound) { 058 Scene.showErrorMessage("Can not find source file \""+sourceName+"\". \n"); 059 } 060 } 061 } 062 063 return (String)mapClassToSourcename.get(className); 064 } 065 066 private void prepareClassPath() { 067 String path = System.getProperty("java.class.path"); 068 StringTokenizer token = new StringTokenizer(path,System.getProperty("path.separator")); 069 070 classPath.clear(); 071 while (token.hasMoreTokens()) { 072 classPath.add(token.nextToken()); 073 } 074 ArrayList additional = SceneSetting.v().getAdditionalClassPath(); 075 for (int i=0; i<additional.size(); i++) { 076 classPath.add(additional.get(i)); 077 } 078 } 079 080 private void prepareSourcePath() { 081 String path = System.getProperty("java.library.path"); 082 StringTokenizer token = new StringTokenizer(path,System.getProperty("path.separator")); 083 084 sourcePath.clear(); 085 while (token.hasMoreTokens()) { 086 sourcePath.add(token.nextToken()); 087 } 088 ArrayList additional = SceneSetting.v().getSourcePath(); 089 for (int i=0; i<additional.size(); i++) { 090 sourcePath.add(additional.get(i)); 091 } 092 } 093 094 private JavaClass loadClass(String className) { 095 JavaClass returnVal = null; 096 097 for (int i=0; i<classPath.size(); i++) { 098 String path = (String)classPath.get(i); 099 File f = new File(path); 100 101 if (!f.exists()) continue; 102 103 if (isArchive(f)) { 104 returnVal = processArchive(className,f); 105 } else if (isClassFile(f)) { 106 returnVal = processClassFile(className, f); 107 } else if (f.isDirectory()) { 108 returnVal = processDirectory(className, f); 109 } 110 111 if (returnVal != null) break; 112 } 113 114 return returnVal; 115 } 116 117 private boolean isArchive(File f) { 118 if (f.isFile() && f.canRead()) { 119 String path; 120 try { 121 path = f.getCanonicalPath(); 122 } catch(IOException e) { 123 return false; 124 } 125 126 if(path.endsWith("zip") || path.endsWith("jar")) { 127 return true; 128 } 129 } 130 return false; 131 } 132 133 private boolean isClassFile(File file) { 134 try { 135 if (!file.isFile()) { 136 return false; 137 } 138 DataInputStream stream = new DataInputStream(new FileInputStream(file)); 139 140 String path = file.getCanonicalPath(); 141 142 if (path.endsWith(".class") && checkMagic(stream)) { 143 return true; 144 } 145 146 return false; 147 } catch (IOException e) { 148 return false; 149 } 150 } 151 152 private boolean checkMagic(DataInputStream classFileStream) { 153 try { 154 return ((classFileStream.readInt() & 0xFFFFFFFFL) == 0xCAFEBABEL); 155 } catch (IOException e) { 156 return false; 157 } 158 } 159 160 private JavaClass processArchive(String className, File archive) { 161 ZipFile zip; 162 163 try { 164 zip = new ZipFile(archive); 165 } catch (ZipException e) { 166 return null; 167 } catch (IOException e) { 168 return null; 169 } 170 171 Enumeration enum = zip.entries(); 172 while (enum.hasMoreElements()) { 173 ZipEntry entry = (ZipEntry) enum.nextElement(); 174 String entryName = entry.getName(), path; 175 176 /* make sure that the class name is valid */ 177 if (entryName != null && entryName.endsWith(".class")) { 178 String tempClassName = entryName.substring(0, entryName.length() - 6).replace('/', '.'); 179 try { 180 path = archive.getCanonicalPath(); 181 if (tempClassName.equals(className)) { 182 return new ClassParser(path, entryName).parse(); 183 } 184 } catch (IOException e) { 185 return null; 186 } 187 } 188 } 189 190 return null; 191 } 192 193 private JavaClass processClassFile(String className, File classFile) { 194 JavaClass javaClass = getClass(classFile); 195 196 if (javaClass == null) return null; 197 /* This method is only invoked when the file exists and is a regular file, 198 so these conditions are not checked again */ 199 String tempClassName = javaClass.getClassName(); 200 if (tempClassName.indexOf('.') >= 0) { 201 /* This class file is part of a package, which does not match 202 the location of the candidate file */ 203 return null; 204 } 205 if (tempClassName.equals(className)) { 206 return javaClass; 207 } 208 return null; 209 } 210 211 private JavaClass processDirectory(String className, File dir) { 212 JavaClass javaClass; 213 214 /* If the class we are looking for is located in this directory, 215 then theoreticalPath must represent its location */ 216 String theoreticalPath = dir.getPath() + File.separator + className.replace('.', File.separatorChar) + ".class"; 217 File theoreticalFile = new File(theoreticalPath); 218 219 220 if (theoreticalFile.exists() && theoreticalFile.isFile()) { 221 javaClass = getClass(theoreticalFile); 222 223 if (javaClass == null) return null; 224 /* This could be a match */ 225 String tempClassName = javaClass.getClassName(); 226 if (tempClassName != null && tempClassName.equals(className)) { 227 /* This is a match */ 228 return javaClass; 229 } 230 } 231 232 return null; 233 } 234 235 private JavaClass getClass(File classFile) { 236 try { 237 DataInputStream stream = new DataInputStream(new FileInputStream(classFile)); 238 239 ClassParser classParser = new ClassParser(stream, classFile.getName()); 240 return classParser.parse(); 241 } catch (FileNotFoundException e) { 242 return null; 243 } catch (IOException e) { 244 return null; 245 } 246 } 247 }